package com.softserveinc.moviedbapp.parser;

import android.sax.Element;
import android.sax.EndElementListener;
import android.sax.EndTextElementListener;
import android.sax.RootElement;
import android.sax.StartElementListener;
import android.util.Log;
import android.util.Xml;

import com.softserveinc.moviedbapp.connection.MovieDBConnectionException;
import com.softserveinc.moviedbapp.model.MovieInfo;

import org.xml.sax.Attributes;

import java.io.IOException;
import java.io.InputStream;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;

public class SAXParserMovieInfo implements IMovieDBMethodGetInfo {

	private static final String TAG = SAXParserMovieInfo.class.getSimpleName();

	/* names of the XML tags */
	static final String ID = "id";
	static final String OVERVIEW = "overview";
	static final String TRAILER = "trailer";
	static final String CAST = "cast";
	static final String PERSON = "person";
	static final String MOVIES = "movies";
	static final String MOVIE = "movie";
	static final String IMAGES = "images";
	static final String IMAGE = "image";
	static final String LAST_MODIFIED_AT = "last_modified_at";

	/* performs actual parsing */
	@Override
	public MovieInfo parseMovieInfo(final InputStream is) throws MovieDBConnectionException {
		Log.d(TAG, "entered parseMovieInfo()");
		final MovieInfo currentMovieInfo = new MovieInfo();

		/* sets the root tag of the xml */
		RootElement rootTag = new RootElement("OpenSearchDescription");
		Element moviesTag = rootTag.getChild(MOVIES);
		Element movieTag = moviesTag.getChild(MOVIE);

		/* get the contents of the id tag */
		movieTag.getChild(ID).setEndTextElementListener(new EndTextElementListener() {
			@Override
			public void end(final String body) {
				currentMovieInfo.setMovieId(Integer.parseInt(body));
			}
		});

		/* get the contents of the overview tag */
		movieTag.getChild(OVERVIEW).setEndTextElementListener(new EndTextElementListener() {
			@Override
			public void end(final String body) {
				currentMovieInfo.setOverview(body);
			}
		});

		/* get the contents of the trailer tag */
		movieTag.getChild(TRAILER).setEndTextElementListener(new EndTextElementListener() {
			@Override
			public void end(final String body) {
				currentMovieInfo.setTrailerUrl(body);
			}
		});

		/* get inside the images tag and get the contents of the image tag */
		Element imagesTag = movieTag.getChild(IMAGES);
		currentMovieInfo.setImagesUrls(new TreeMap<String, List<String>>());

		imagesTag.getChild(IMAGE).setStartElementListener(new StartElementListener() {
			@Override
			public void start(final Attributes attributes) {
				String size = attributes.getValue(2);
				String type = attributes.getValue(0);
				if (type.equals("backdrop") && size.equals("thumb") || size.equals("poster") ) {
					/* add image type and size to ArrayList */
					List<String> typeSizeList = new ArrayList<String>();
					typeSizeList.add(type);
					typeSizeList.add(size);

					/* then get the image url and use it as a map key and type-size list as values */
					currentMovieInfo.getImagesUrls().put(attributes.getValue(1), typeSizeList);
				}
			}
		});

		/* get inside the images tag and get the contents of the image tag */
		Element castTag = movieTag.getChild(CAST);
		currentMovieInfo.setCast(new ArrayList<String>());

		castTag.getChild(PERSON).setStartElementListener(new StartElementListener() {
			@Override
			public void start(final Attributes attributes) {

				/* choose the actors from the cast */
				if (attributes.getValue(2).equals("Actor")) {
					currentMovieInfo.getCastList().add(attributes.getValue("name"));
				}
			}
		});

		movieTag.getChild(LAST_MODIFIED_AT).setEndTextElementListener(new EndTextElementListener() {
			@Override
			public void end(final String body) {
				Log.d(TAG, "parser " + body + " </last_modified_at> ");
				currentMovieInfo.setLastModifiedAt(body);
			}
		});

		/* for debug purposes only */
		rootTag.setEndElementListener(new EndElementListener() {

			@Override
			public void end() {
				Log.d(TAG, "parser </OpenSearchDescription> ");

			}
		});

		/* start parsing */

		try {
			Log.d(TAG, "STARTED PARSING movie info with ANDROID SAX");
			Xml.parse(is, Xml.Encoding.UTF_8, rootTag.getContentHandler());
			Log.d(TAG, "\nSUCCESSFULLY COMPLETED PARSING movie info with ANDROID SAX");
		} catch (SocketTimeoutException e) {
			Log.e(TAG, "SocketTimeoutException. Gonna throw my connection exception", e);
			throw new MovieDBConnectionException("SocketTimeoutException");
		} catch (Exception e) {
			Log.e(TAG, "Parsing movie details failed. ", e);
			throw new MovieDBConnectionException("SocketTimeoutException");
		} finally {
			try {
				is.close();
			} catch (IOException e) {
				Log.w(TAG, "unable to close input stream", e);
			}
		}

		return currentMovieInfo;

	}
}
